package ro.flashbite.game_engine.controller
{
	import flash.net.SharedObject;
	import flash.utils.Dictionary;
	
	import ro.flashbite.helpers.DictionaryHelpers;
	import ro.flashbite.interfaces.IDestroyable;
	import ro.flashbite.loggers.ILogger;
	import ro.flashbite.loggers.LoggerFactory;
	
	public final class SharedDataManager implements IDestroyable
	{
		/**
		 * location in sharedObject were data will be saved 
		 */		
		private var _gameID			:	String;
		/**
		 * holds a shared object that can be modified from applets
		 */		
		private var _sharedData		:	Dictionary;
		/**
		 * flash sharedObject 
		 */		
		private var _sharedObject	:	SharedObject;
		/**
		 * logger for debug purpose 
		 */		
		private var _logger			:	ILogger;
		
		// ================================================================================================================================
		// CONTRUCTOR
		// ================================================================================================================================
		
		public function SharedDataManager(gameID:String)
		{
			_constructor(gameID);
		}
		private function _constructor(gameID:String):void
		{
			_gameID = gameID;
			
			_logger = LoggerFactory.getLogger("SharedDataManager");
			
			readFromSharedObject(true);
		}
		
		// ================================================================================================================================
		// PUBLIC
		// ================================================================================================================================
		
		/**
		 * Each applet can store shared data here
		 *  
		 * @param id = unique id of data to store
		 * @param data = the object to 'share' (store)
		 * @param overwrite = if set to true, the old object stored on same location will be deleted
		 * @return : (Boolean) true if saving was complete, false otherwise
		 */	
		public function saveData(id:String, data:Object, overwrite:Boolean = true):Boolean 
		{
			if (_sharedData) {
				return append(id, data, overwrite);
			} else {
				//make a retry
				readFromSharedObject();
				return append(id, data, overwrite);
			}
			
			return false;
		}
		
		/**
		 * Each applet can get shared data from here
		 *  
		 * @param id = the unique id of shared data
		 * @return the object with specified id
		 */	
		public function getData(id:String):Object 
		{ 
			if (_sharedData) return (_sharedData[id] as Object);
			return null;
		}
		
		// ================================================================================================================================
		// PRIVATE
		// ================================================================================================================================
		
		private function append(id:String, data:Object, overwrite:Boolean = true):Boolean
		{
			if (_sharedData) {
				if (_sharedData[id] == null) {
					_sharedData[id] = data;
				} else {
					if (overwrite) {
						delete _sharedData[id];
						_sharedData[id] = data;
					}
				}
				
				//save locally saved data
				if (_sharedObject) return saveLocalSharedObject();
				else {
					//retry to save
					try {
						_sharedObject = SharedObject.getLocal(_gameID, "/");
						return saveLocalSharedObject();
					} catch (e:Error) { _logger.error("Couldn't save in SharedObject. Couldn't get SharedObject"); }
				}
			} else {
				_logger.error("Couldn't save in SharedObject. Couldn't get SharedObject");
			}
			
			return false;
		}
		
		private function saveLocalSharedObject():Boolean
		{
			_sharedObject.data.sharedData = serialize(_sharedData);
			_sharedObject.flush();
			
			return readFromSharedObject();
		}
		
		private function readFromSharedObject(firstTime:Boolean = false):Boolean
		{
			try {
				_sharedObject = SharedObject.getLocal(_gameID, "/");
				if (_sharedObject.data) {
					if (_sharedObject.data.sharedData) _sharedData = unserialize(_sharedObject.data.sharedData);
					else {
						if (firstTime) {
							_sharedData = new Dictionary(true);
							saveLocalSharedObject();
						}
					}
					return true;
				} else return false;
			} catch (e:Error) { _logger.error("FATAL!!!! Couldn't load data from sharedObject"); }
			
			return false;
		}
		
		private function serialize(data:Dictionary):Object
		{
			var serializedObject:Object = {};
			
			for (var key:* in data) {
				serializedObject[key] = data[key];
			}
			
			return serializedObject;
		}
		private function unserialize(obj:Object):Dictionary
		{
			var unserializedDict:Dictionary = new Dictionary(true);
			
			for (var key:* in obj) {
				unserializedDict[key] = obj[key];
			}
			
			return unserializedDict;
		}
		
		// ================================================================================================================================
		// DESTRUCTOR
		// ================================================================================================================================
		
		public function destroy():void
		{
			if (_sharedData && _sharedObject) saveLocalSharedObject();
			
			if (_sharedData) {
				DictionaryHelpers.clear(_sharedData);
				_sharedData = null;
			}
			_sharedObject = null;
			_gameID = null;
			
			_logger = null;
		}
	}
}